//
// Created by antler on 2018/12/5.
//

#include "lprefix.h"

#include <string>

#include "lua.hpp"
#include "luaext.hpp"

extern "C" {
#include "lua_cjson.h"
};

#include "log.h"
#include "GlobalMacros.h"

#include "UI.h"
#include "UIContext.h"
#include "UIView.h"

static int ui_tostring(lua_State *L) {
    lua_pushfstring(L, "class: %p", lua_topointer(L, 1));
    return 1;
}

static int ui_toast(lua_State *L) {
    const char *msg = luaL_checkstring(L, 1);
    int length = luaL_optint(L, 2, UI::TOAST::LENGTH_SHORT);
    UI::getInstance()->toast(msg, length);
    return 0;
}

static int ui_createContext(lua_State *L) {
    std::string layout;
    std::string style;

    int type = lua_type(L, 1);
    if (type == LUA_TTABLE) {
        layout = toluahelper_table2json(L, 1);
    } else if (type == LUA_TSTRING) {
        layout = lua_tostring(L, 1);
    }

    if (!layout.empty()) {
        type = lua_type(L, 2);
        if (type == LUA_TTABLE) {
            style = toluahelper_table2json(L, 2);
        } else if (type == LUA_TSTRING) {
            style = lua_tostring(L, 2);
        }

        UIContext *uiContext = UI::getInstance()->createContext(layout, style);
        if (uiContext) {
            tolua_pushusertype_and_takeownership(L, uiContext, USERTYPE_UICONTEXT);
        }
    } else {
        tolua_Error tolua_err = {1, 0, "string or table"};
        tolua_error(L, "#fUI.createContext", &tolua_err);
    }

    return 1;
}

static int ui_register(lua_State *L) {

    std::string name = luaL_checkstring(L, 1);

    std::string layout;
    int type = lua_type(L, 2);
    if (type == LUA_TTABLE) {
        layout = toluahelper_table2json(L, 2);
    } else if (type == LUA_TSTRING) {
        layout = lua_tostring(L, 2);
    } else {
        tolua_Error tolua_err = {2, 0, "string or table"};
        tolua_error(L, "#fUI.register", &tolua_err);
    }

    UI::getInstance()->registerUI(name, layout);
    return 0;
}

static const luaL_Reg ui_funcs[] = {
        {"__tostring",    ui_tostring},
        {"toast",         ui_toast},
        {"createContext", ui_createContext},
        {"register",      ui_register},
        {nullptr,         nullptr}
};

// TYPE
static int get_TYPE_UNKNOWN(lua_State *L) {
    lua_pushinteger(L, UI::TYPE::UNKNOWN);
    return 1;
}

static int get_TYPE_CONTAINER(lua_State *L) {
    lua_pushinteger(L, UI::TYPE::CONTAINER);
    return 1;
}

static int get_TYPE_DIV(lua_State *L) {
    lua_pushinteger(L, UI::TYPE::DIV);
    return 1;
}

static int get_TYPE_TEXT(lua_State *L) {
    lua_pushinteger(L, UI::TYPE::TEXT);
    return 1;
}

static int get_TYPE_IMAGE(lua_State *L) {
    lua_pushinteger(L, UI::TYPE::IMAGE);
    return 1;
}

static int get_TYPE_SCROLLER(lua_State *L) {
    lua_pushinteger(L, UI::TYPE::SCROLLER);
    return 1;
}

static int get_TYPE_LIST(lua_State *L) {
    lua_pushinteger(L, UI::TYPE::LIST);
    return 1;
}

static int get_TYPE_SWITCH(lua_State *L) {
    lua_pushinteger(L, UI::TYPE::SWITCH);
    return 1;
}

static int get_TYPE_INPUT(lua_State *L) {
    lua_pushinteger(L, UI::TYPE::INPUT);
    return 1;
}

static int get_TYPE_TEXTAREA(lua_State *L) {
    lua_pushinteger(L, UI::TYPE::TEXTAREA);
    return 1;
}

static int get_TYPE_VIDEO(lua_State *L) {
    lua_pushinteger(L, UI::TYPE::VIDEO);
    return 1;
}

static int get_TYPE_INDICATOR(lua_State *L) {
    lua_pushinteger(L, UI::TYPE::INDICATOR);
    return 1;
}

static int get_TYPE_WEB(lua_State *L) {
    lua_pushinteger(L, UI::TYPE::WEB);
    return 1;
}

static int get_TYPE_LOADING(lua_State *L) {
    lua_pushinteger(L, UI::TYPE::LOADING);
    return 1;
}

// ACTION
static int get_ACTION_APPEAR(lua_State *L) {
    lua_pushinteger(L, UI::ACTION::APPEAR);
    return 1;
}

static int get_ACTION_DISAPPER(lua_State *L) {
    lua_pushinteger(L, UI::ACTION::DISAPPER);
    return 1;
}

static int get_ACTION_CLICK(lua_State *L) {
    lua_pushinteger(L, UI::ACTION::CLICK);
    return 1;
}

static int get_ACTION_LONG_PRESS(lua_State *L) {
    lua_pushinteger(L, UI::ACTION::LONG_PRESS);
    return 1;
}

static int get_ACTION_SWIPE(lua_State *L) {
    lua_pushinteger(L, UI::ACTION::SWIPE);
    return 1;
}

// PSEUDO
static int get_PSEUDO_ACTIVE(lua_State *L) {
    lua_pushstring(L, UI::PSEUDO::ACTIVE);
    return 1;
}

static int get_PSEUDO_FOCUS(lua_State *L) {
    lua_pushstring(L, UI::PSEUDO::FOCUS);
    return 1;
}

static int get_PSEUDO_ENABLED(lua_State *L) {
    lua_pushstring(L, UI::PSEUDO::ENABLED);
    return 1;
}

static int get_PSEUDO_DISABLED(lua_State *L) {
    lua_pushstring(L, UI::PSEUDO::DISABLED);
    return 1;
}

// TOAST
static int get_TOAST_LENGTH_SHORT(lua_State *L) {
    lua_pushinteger(L, UI::TOAST::LENGTH_SHORT);
    return 1;
}

static int get_TOAST_LENGTH_LONG(lua_State *L) {
    lua_pushinteger(L, UI::TOAST::LENGTH_LONG);
    return 1;
}

// UIContext
int uicontext_destructor(lua_State *L) {
    UIContext *self = (UIContext *) tolua_tousertype(L, 1, 0);
    LOGV("uicontext:destructor self:%p", self);
    SAFE_DELETE(self);
    return 0;
}

static int uicontext_tostring(lua_State *L) {
    lua_pushfstring(L, "class: %p", lua_topointer(L, 1));
    return 1;
}

static int uicontext_show(lua_State *L) {
    UIContext *self = (UIContext *) toluahelper_tousertype(L, 1, USERTYPE_UICONTEXT, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in function 'show'", nullptr);
    }

    self->show();
    return 0;
}

static int uicontext_close(lua_State *L) {
    UIContext *self = (UIContext *) toluahelper_tousertype(L, 1, USERTYPE_UICONTEXT, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in function 'close'", nullptr);
    }

    self->close();
    return 0;
}

static int uicontext_getRootView(lua_State *L) {
    UIContext *self = (UIContext *) toluahelper_tousertype(L, 1, USERTYPE_UICONTEXT, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in function 'getRootView'", nullptr);
    }

    UIView *uiView = self->getRootView();
    if (uiView) {
        tolua_pushusertype_and_takeownership(L, uiView, USERTYPE_UIVIEW);
    } else {
        lua_pushnil(L);
    }
    return 1;
}

static int uicontext_findView(lua_State *L) {
    UIContext *self = (UIContext *) toluahelper_tousertype(L, 1, USERTYPE_UICONTEXT, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in function 'findView'", nullptr);
    }

    const char *id = luaL_checkstring(L, 2);

    UIView *uiView = self->findView(id);
    if (uiView) {
        tolua_pushusertype_and_takeownership(L, uiView, USERTYPE_UIVIEW);
    } else {
        lua_pushnil(L);
    }
    return 1;
}

static int uicontext_createView(lua_State *L) {
    UIContext *self = (UIContext *) toluahelper_tousertype(L, 1, USERTYPE_UICONTEXT, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in function 'createView'", nullptr);
    }

    std::string layout;
    int type = lua_type(L, 2);
    if (type == LUA_TTABLE) {
        layout = toluahelper_table2json(L, 2);
    } else if (type == LUA_TSTRING) {
        layout = lua_tostring(L, 2);
    } else {
        tolua_Error tolua_err = {1, 0, "string or table"};
        tolua_error(L, "#fuicontext:createView", &tolua_err);
    }

    UIView *uiView = self->createView(layout);
    if (uiView) {
        tolua_pushusertype_and_takeownership(L, uiView, USERTYPE_UIVIEW);
    } else {
        lua_pushnil(L);
    }
    return 1;
}

static const luaL_Reg uicontext_funcs[] = {
        {"__tostring",  uicontext_tostring},
        {"show",        uicontext_show},
        {"close",       uicontext_close},
        {"getRootView", uicontext_getRootView},
        {"findView",    uicontext_findView},
        {"createView",  uicontext_createView},
        {nullptr,       nullptr}
};

// UIView
int uiview_destructor(lua_State *L) {
    UIView *self = (UIView *) tolua_tousertype(L, 1, 0);
    LOGV("uiview:destructor self:%p", self);
    SAFE_DELETE(self);
    return 0;
}

static int uiview_tostring(lua_State *L) {
    lua_pushfstring(L, "class: %p", lua_topointer(L, 1));
    return 1;
}

static int uiview_getID(lua_State *L) {
    UIView *self = (UIView *) toluahelper_tousertype(L, 1, USERTYPE_UIVIEW, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in function 'getID'", nullptr);
    }

    const std::string &id = self->getID();
    lua_pushstring(L, id.c_str());
    return 1;
}

static int uiview_getType(lua_State *L) {
    UIView *self = (UIView *) toluahelper_tousertype(L, 1, USERTYPE_UIVIEW, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in function 'getType'", nullptr);
    }

    int type = self->getType();
    lua_pushinteger(L, type);
    return 1;
}

static int uiview_getAttr(lua_State *L) {
    UIView *self = (UIView *) toluahelper_tousertype(L, 1, USERTYPE_UIVIEW, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in function 'getAttr'", nullptr);
    }

    const char *key = luaL_checkstring(L, 1);

    return 0;
}

static int uiview_getAttrs(lua_State *L) {
    UIView *self = (UIView *) toluahelper_tousertype(L, 1, USERTYPE_UIVIEW, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in function 'getAttrs'", nullptr);
    }

    std::string attrs = self->getAttrs();
    if (attrs.empty()) {
        attrs = "{}";
    }

    toluahelper_json2table(L, attrs);
    return 1;
}

static int uiview_getStyle(lua_State *L) {
    UIView *self = (UIView *) toluahelper_tousertype(L, 1, USERTYPE_UIVIEW, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in function 'getStyle'", nullptr);
    }

    const char *key = luaL_checkstring(L, 1);

    return 0;
}

static int uiview_getStyles(lua_State *L) {
    UIView *self = (UIView *) toluahelper_tousertype(L, 1, USERTYPE_UIVIEW, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in function 'getStyles'", nullptr);
    }

    std::string styles = self->getStyles();
    if (styles.empty()) {
        styles = "{}";
    }

    toluahelper_json2table(L, styles);
    return 1;
}

static int uiview_getPseudoStyle(lua_State *L) {
    UIView *self = (UIView *) toluahelper_tousertype(L, 1, USERTYPE_UIVIEW, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in function 'getPseudoStyle'", nullptr);
    }

    const char *key = luaL_checkstring(L, 1);

    return 0;
}

static int uiview_getPseudoStyles(lua_State *L) {
    UIView *self = (UIView *) toluahelper_tousertype(L, 1, USERTYPE_UIVIEW, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in function 'getPseudoStyles'", nullptr);
    }

    std::string styles = self->getPseudoStyles();
    if (styles.empty()) {
        styles = "{}";
    }

    toluahelper_json2table(L, styles);
    return 1;
}

static int uiview_setAttr(lua_State *L) {
    UIView *self = (UIView *) toluahelper_tousertype(L, 1, USERTYPE_UIVIEW, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in function 'setAttr'", nullptr);
    }

    int type = lua_type(L, 2);
    switch (type) {
        case LUA_TSTRING: {
            const char *key = lua_tostring(L, 2);

            type = lua_type(L, 3);
            switch (type) {
                case LUA_TBOOLEAN: {
                    toluahelper_keyvalue2table(L, key, lua_toboolean(L, 3) ? true : false);
                    self->setAttr(toluahelper_table2json(L, lua_gettop(L)));
                    break;
                }
                case LUA_TNUMBER: {
                    toluahelper_keyvalue2table(L, key, lua_tonumber(L, 3));
                    self->setAttr(toluahelper_table2json(L, lua_gettop(L)));
                    break;
                }
                case LUA_TSTRING: {
                    const std::string value = lua_tostring(L, 3);
                    toluahelper_keyvalue2table(L, key, value);
                    self->setAttr(toluahelper_table2json(L, lua_gettop(L)));
                    break;
                }
                default: {
                    tolua_Error tolua_err = {2, 0, "bool or number or string"};
                    tolua_error(L, "#fuiview:setAttr", &tolua_err);
                    break;
                }
            }
            break;
        }
        case LUA_TTABLE: {
            self->setAttr(toluahelper_table2json(L, 2));
            break;
        }
        default: {
            tolua_Error tolua_err = {1, 0, "string or table"};
            tolua_error(L, "#fuiview:setAttr", &tolua_err);
            break;
        }
    }

    return 0;
}

static int uiview_setStyle(lua_State *L) {
    UIView *self = (UIView *) toluahelper_tousertype(L, 1, USERTYPE_UIVIEW, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in function 'setStyle'", nullptr);
    }

    int type = lua_type(L, 2);
    switch (type) {
        case LUA_TSTRING: {
            const char *key = lua_tostring(L, 2);

            type = lua_type(L, 3);
            switch (type) {
                case LUA_TBOOLEAN: {
                    toluahelper_keyvalue2table(L, key, lua_toboolean(L, 3) ? true : false);
                    self->setStyle(toluahelper_table2json(L, lua_gettop(L)));
                    break;
                }
                case LUA_TNUMBER: {
                    toluahelper_keyvalue2table(L, key, lua_tonumber(L, 3));
                    self->setStyle(toluahelper_table2json(L, lua_gettop(L)));
                    break;
                }
                case LUA_TSTRING: {
                    const std::string value = lua_tostring(L, 3);
                    toluahelper_keyvalue2table(L, key, value);
                    self->setStyle(toluahelper_table2json(L, lua_gettop(L)));
                    break;
                }
                default: {
                    tolua_Error tolua_err = {2, 0, "bool or number or string"};
                    tolua_error(L, "#fuiview:setStyle", &tolua_err);
                    break;
                }
            }
            break;
        }
        case LUA_TTABLE: {
            self->setStyle(toluahelper_table2json(L, 2));
            break;
        }
        default: {
            tolua_Error tolua_err = {1, 0, "string or table"};
            tolua_error(L, "#fuiview:setStyle", &tolua_err);
            break;
        }
    }

    return 0;
}

static int uiview_setPseudoStyle(lua_State *L) {
    UIView *self = (UIView *) toluahelper_tousertype(L, 1, USERTYPE_UIVIEW, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in function 'setPseudoStyle'", nullptr);
    }

    const char *pseudo = luaL_checkstring(L, 2);

    int type = lua_type(L, 3);
    switch (type) {
        case LUA_TSTRING: {
            const char *key = lua_tostring(L, 3);

            type = lua_type(L, 4);
            switch (type) {
                case LUA_TBOOLEAN: {
                    toluahelper_keyvalue2table(L, key, lua_toboolean(L, 4) ? true : false);
                    self->setPseudoStyle(pseudo, toluahelper_table2json(L, lua_gettop(L)));
                    break;
                }
                case LUA_TNUMBER: {
                    toluahelper_keyvalue2table(L, key, lua_tonumber(L, 4));
                    self->setPseudoStyle(pseudo, toluahelper_table2json(L, lua_gettop(L)));
                    break;
                }
                case LUA_TSTRING: {
                    const std::string value = lua_tostring(L, 4);
                    toluahelper_keyvalue2table(L, key, value);
                    self->setPseudoStyle(pseudo, toluahelper_table2json(L, lua_gettop(L)));
                    break;
                }
                default: {
                    tolua_Error tolua_err = {3, 0, "bool or number or string"};
                    tolua_error(L, "#fuiview:setPseudoStyle", &tolua_err);
                    break;
                }
            }
            break;
        }
        case LUA_TTABLE: {
            self->setPseudoStyle(pseudo, toluahelper_table2json(L, 3));
            break;
        }
        default: {
            tolua_Error tolua_err = {2, 0, "string or table"};
            tolua_error(L, "#fuiview:setPseudoStyle", &tolua_err);
            break;
        }
    }

    return 0;
}

static int uiview_subviewsCount(lua_State *L) {
    UIView *self = (UIView *) toluahelper_tousertype(L, 1, USERTYPE_UIVIEW, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in function 'subviewsCount'", nullptr);
    }

    lua_pushinteger(L, self->subviewsCount());
    return 1;
}

static int uiview_getSubview(lua_State *L) {
    UIView *self = (UIView *) toluahelper_tousertype(L, 1, USERTYPE_UIVIEW, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in function 'getSubview'", nullptr);
    }

    int index = luaL_checkint(L, 2);

    UIView *uiview = self->getSubview(index);
    if (uiview) {
        tolua_pushusertype_and_takeownership(L, uiview, USERTYPE_UIVIEW);
    } else {
        lua_pushnil(L);
    }
    return 1;
}

static int uiview_addSubview(lua_State *L) {
    UIView *self = (UIView *) toluahelper_tousertype(L, 1, USERTYPE_UIVIEW, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in function 'addSubview'", nullptr);
    }

    tolua_Error tolua_err;
    UIView *uiview = (UIView *) toluahelper_tousertype(L, 2, USERTYPE_UIVIEW, nullptr, &tolua_err);
    if (!uiview) {
        tolua_error(L, "#fuiview:addSubview", &tolua_err);
    }

    int index = luaL_optint(L, 3, -1);

    self->addSubview(uiview, index);
    return 0;
}

static int uiview_removeSubview(lua_State *L) {
    UIView *self = (UIView *) toluahelper_tousertype(L, 1, USERTYPE_UIVIEW, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in function 'removeSubview'", nullptr);
    }

    int index = luaL_checkint(L, 2);

    self->removeSubview(index);
    return 0;
}

static int uiview_removeFromParent(lua_State *L) {
    UIView *self = (UIView *) toluahelper_tousertype(L, 1, USERTYPE_UIVIEW, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in function 'removeFromParent'", nullptr);
    }

    self->removeFromParent();
    return 0;
}

static int uiview_setActionCallback(lua_State *L) {
    UIView *self = (UIView *) toluahelper_tousertype(L, 1, USERTYPE_UIVIEW, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in function 'setActionCallback'", nullptr);
    }

    int action = luaL_checkint(L, 2);
    int funID = toluahelper_ref_function(L, 3);
    self->setActionCallback(action, funID);
    return 0;
}

static int uiview_toJson(lua_State *L) {
    UIView *self = (UIView *) toluahelper_tousertype(L, 1, USERTYPE_UIVIEW, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in function 'toJson'", nullptr);
    }

    lua_pushstring(L, self->toJson().c_str());
    return 1;
}

static const luaL_Reg uiview_funcs[] = {
        {"__tostring",        uiview_tostring},
        {"getID",             uiview_getID},
        {"getType",           uiview_getType},
        {"getAttr",           uiview_getAttr},
        {"getAttrs",          uiview_getAttrs},
        {"getStyle",          uiview_getStyle},
        {"getStyles",         uiview_getStyles},
        {"getPseudoStyle",    uiview_getPseudoStyle},
        {"getPseudoStyles",   uiview_getPseudoStyles},
        {"setAttr",           uiview_setAttr},
        {"setStyle",          uiview_setStyle},
        {"setPseudoStyle",    uiview_setPseudoStyle},
        {"subviewsCount",     uiview_subviewsCount},
        {"getSubview",        uiview_getSubview},
        {"addSubview",        uiview_addSubview},
        {"removeSubview",     uiview_removeSubview},
        {"removeFromParent",  uiview_removeFromParent},
        {"setActionCallback", uiview_setActionCallback},
        {"toJson",            uiview_toJson},
        {nullptr,             nullptr}
};

static const luaL_Reg global_funcs[] = {
        {"dialog", ui_toast},
        {nullptr,  nullptr}
};

LUAMOD_API int luaopen_ui(lua_State *L) {
    tolua_open(L);

    tolua_module(L, nullptr, 0);
    tolua_beginmodule(L, nullptr);
    {
        toluahelper_setfunc(L, global_funcs);

        // UI
        tolua_usertype(L, USERTYPE_UI);
        tolua_cclass(L, CLASSNAME_UI, USERTYPE_UI, "", nullptr);

        tolua_beginmodule(L, CLASSNAME_UI);
        {
            toluahelper_setfunc(L, ui_funcs);

            {
                tolua_usertype(L, USERTYPE_UI_TYPE);
                tolua_cclass(L, CLASSNAME_UI_TYPE, USERTYPE_UI_TYPE, "", nullptr);

                tolua_beginmodule(L, CLASSNAME_UI_TYPE);
                {
                    TOLUAHELPER_CLASS_CONST_VARIABLE_NS(L, TYPE, UNKNOWN);
                    TOLUAHELPER_CLASS_CONST_VARIABLE_NS(L, TYPE, CONTAINER);
                    TOLUAHELPER_CLASS_CONST_VARIABLE_NS(L, TYPE, DIV);
                    TOLUAHELPER_CLASS_CONST_VARIABLE_NS(L, TYPE, TEXT);
                    TOLUAHELPER_CLASS_CONST_VARIABLE_NS(L, TYPE, IMAGE);
                    TOLUAHELPER_CLASS_CONST_VARIABLE_NS(L, TYPE, SCROLLER);
                    TOLUAHELPER_CLASS_CONST_VARIABLE_NS(L, TYPE, LIST);
                    TOLUAHELPER_CLASS_CONST_VARIABLE_NS(L, TYPE, SWITCH);
                    TOLUAHELPER_CLASS_CONST_VARIABLE_NS(L, TYPE, INPUT);
                    TOLUAHELPER_CLASS_CONST_VARIABLE_NS(L, TYPE, TEXTAREA);
                    TOLUAHELPER_CLASS_CONST_VARIABLE_NS(L, TYPE, VIDEO);
                    TOLUAHELPER_CLASS_CONST_VARIABLE_NS(L, TYPE, INDICATOR);
                    TOLUAHELPER_CLASS_CONST_VARIABLE_NS(L, TYPE, WEB);
                    TOLUAHELPER_CLASS_CONST_VARIABLE_NS(L, TYPE, LOADING);
                }
                tolua_endmodule(L);
            }

            {
                tolua_usertype(L, USERTYPE_UI_ACTION);
                tolua_cclass(L, CLASSNAME_UI_ACTION, USERTYPE_UI_ACTION, "", nullptr);

                tolua_beginmodule(L, CLASSNAME_UI_ACTION);
                {
                    TOLUAHELPER_CLASS_CONST_VARIABLE_NS(L, ACTION, APPEAR);
                    TOLUAHELPER_CLASS_CONST_VARIABLE_NS(L, ACTION, DISAPPER);
                    TOLUAHELPER_CLASS_CONST_VARIABLE_NS(L, ACTION, CLICK);
                    TOLUAHELPER_CLASS_CONST_VARIABLE_NS(L, ACTION, LONG_PRESS);
                    TOLUAHELPER_CLASS_CONST_VARIABLE_NS(L, ACTION, SWIPE);
                }
                tolua_endmodule(L);
            }

            {
                tolua_usertype(L, USERTYPE_UI_PSEUDO);
                tolua_cclass(L, CLASSNAME_UI_PSEUDO, USERTYPE_UI_PSEUDO, "", nullptr);

                tolua_beginmodule(L, CLASSNAME_UI_PSEUDO);
                {
                    TOLUAHELPER_CLASS_CONST_VARIABLE_NS(L, PSEUDO, ACTIVE);
                    TOLUAHELPER_CLASS_CONST_VARIABLE_NS(L, PSEUDO, FOCUS);
                    TOLUAHELPER_CLASS_CONST_VARIABLE_NS(L, PSEUDO, ENABLED);
                    TOLUAHELPER_CLASS_CONST_VARIABLE_NS(L, PSEUDO, DISABLED);
                }
                tolua_endmodule(L);
            }

            {
                tolua_usertype(L, USERTYPE_UI_TOAST);
                tolua_cclass(L, CLASSNAME_UI_TOAST, USERTYPE_UI_TOAST, "", nullptr);

                tolua_beginmodule(L, CLASSNAME_UI_TOAST);
                {
                    TOLUAHELPER_CLASS_CONST_VARIABLE_NS(L, TOAST, LENGTH_SHORT);
                    TOLUAHELPER_CLASS_CONST_VARIABLE_NS(L, TOAST, LENGTH_LONG);
                }
                tolua_endmodule(L);
            }
        }
        tolua_endmodule(L);

        // UIContext
        tolua_usertype(L, USERTYPE_UICONTEXT);
        tolua_cclass(L, CLASSNAME_UICONTEXT, USERTYPE_UICONTEXT, "", uicontext_destructor);

        tolua_beginmodule(L, CLASSNAME_UICONTEXT);
        {
            toluahelper_setfunc(L, uicontext_funcs);

        }
        tolua_endmodule(L);

        // UIView
        tolua_usertype(L, USERTYPE_UIVIEW);
        tolua_cclass(L, CLASSNAME_UIVIEW, USERTYPE_UIVIEW, "", uiview_destructor);

        tolua_beginmodule(L, CLASSNAME_UIVIEW);
        {
            toluahelper_setfunc(L, uiview_funcs);
        }
        tolua_endmodule(L);

    }
    tolua_endmodule(L);
    return 0;
}



